﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using C1.Win.C1FlexGrid;

namespace SocketClient
{
    public partial class frmReplyManager2 : Form
    {
        #region Members
        private const int ReplyGroupLevel = 0;
        private const int ReplyItemLevel = 1;
        private const int TreeColumnIndex = 1;
        private const int ColumnMinWidth = 20;
        private int[] DefaultColumnWidths = new int[] { 20, 200, 150, 150, 100 };
        private string[] ColumnNames = new string[] { "", "名称", "接收(Hex)", "回复(Hex)", "描述" };

        private ReplyList _replys;
        #endregion //Members

        #region frmReplyManager2
        public frmReplyManager2(ReplyList replys)
        {
            InitializeComponent();
            this.MaximizeBox = false;
            this.MinimizeBox = false;
            this.FormClosing += new FormClosingEventHandler(frmReplyManager2_FormClosing);
            _flex.AfterEdit += new C1.Win.C1FlexGrid.RowColEventHandler(_flex_AfterEdit);
            _flex.MouseDoubleClick += new MouseEventHandler(_flex_MouseDoubleClick);
            _replys = replys;
            InitFlexGrid();
        }
        #endregion //frmReplyManager2

        #region _flex_MouseDoubleClick
        private void _flex_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                if (_flex.Row > 0)
                {
                    Row row = _flex.Rows[_flex.Row];
                    if (row.UserData is ReplyGroup)
                    {
                        tsbEdit_Click (null, null);
                    }
                    if (row.UserData is ReplyItem)
                    {
                        tsbEdit_Click(null, null);
                    }
                }
            }
        }
        #endregion //_flex_MouseDoubleClick

        #region frmReplyManager2_FormClosing
        /// <summary>
        /// 
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void frmReplyManager2_FormClosing(object sender, FormClosingEventArgs e)
        {
            foreach (C1.Win.C1FlexGrid.Row row in this._flex.Rows)
            {
                if (row.UserData is ReplyItem)
                {
                    ReplyItem ri = (ReplyItem)row.UserData;
                    C1.Win.C1FlexGrid.CheckEnum ce = _flex.GetCellCheck(row.Index, TreeColumnIndex);
                    ri.Enabled = ce == C1.Win.C1FlexGrid.CheckEnum.Checked ||
                        ce == C1.Win.C1FlexGrid.CheckEnum.TSChecked;
                }
            }
            List<int> widths = new List<int>();
            foreach (C1.Win.C1FlexGrid.Column col in _flex.Cols)
            {
                widths.Add(col.Width);
            }
            App.Default.Config.ReplyManagerColumnWidths = widths;
            App.Default.Config.ReplyManagerSize = this.Size;
        }
        #endregion //frmReplyManager2_FormClosing

        #region InitFlexGrid
        private void InitFlexGrid()
        {
            _flex.Cols.Count = ColumnNames.Length;
            _flex.AllowSorting = C1.Win.C1FlexGrid.AllowSortingEnum.None;
            _flex.Cols.MinSize = ColumnMinWidth;
            _flex.ExtendLastCol = true;
            _flex.Tree.Column = TreeColumnIndex;
            _flex.Rows.Count = 1;

            List<int> colWidths = App.Default.Config.ReplyManagerColumnWidths;
            if (colWidths.Count < ColumnNames.Length)
            {
                colWidths = new List<int>(DefaultColumnWidths);
                App.Default.Config.ReplyManagerColumnWidths = colWidths;
            }
            this.Size = App.Default.Config.ReplyManagerSize;

            //string[] colNames = ColumnNames.Split('|');

            for (int i = 0; i < ColumnNames.Length; i++)
            {
                _flex[0, i] = ColumnNames[i];
                C1.Win.C1FlexGrid.Column col = _flex.Cols[i];
                if (i != TreeColumnIndex)
                {
                    col.AllowEditing = false;
                }
                col.Width = colWidths[i];
                col.TextAlign = C1.Win.C1FlexGrid.TextAlignEnum.LeftCenter;
                col.AllowMerging = true;
            }

            SortedDictionary<ReplyGroup, ReplyList> gs = Sp();
            foreach (var item in gs)
            {
                ReplyGroup group = item.Key;
                ReplyList replys = item.Value;
                replys.Sort();
                CheckEnum checkEnum = GetGroupCheckEnum(group);
                AddReplyGroup(group, checkEnum);

                foreach (ReplyItem ri in replys)
                {
                    AddReplyItem(ri);
                }
            }
            _flex.AllowMerging = AllowMergingEnum.Nodes;
            foreach (Row row in _flex.Rows)
            {
                if (row.IsNode)
                {
                    row.AllowMerging = true;
                }
            }
        }
        #endregion //InitFlexGrid

        #region GetGroupCheckEnum
        private CheckEnum GetGroupCheckEnum(ReplyGroup group)
        {
            int count = 0;
            int enabledCount = 0;
            foreach (ReplyItem ri in App.Default.ReplyManager.ReplyCollection)
            {
                if (ri.ReplyGroup == group)
                {
                    count++;
                    enabledCount += ri.Enabled ? 1 : 0;
                }
            }

            if (enabledCount == 0)
            {
                return CheckEnum.TSUnchecked;
            }
            else if (enabledCount == count)
            {
                return CheckEnum.TSChecked;
            }
            else
            {
                return CheckEnum.TSGrayed;
            }
        }
        #endregion //GetGroupCheckEnum

        #region AddReplyGroup
        private C1.Win.C1FlexGrid.Node AddReplyGroup(ReplyGroup group, C1.Win.C1FlexGrid.CheckEnum checkEnumStatus)
        {
            var g = _flex;
            var node = g.Rows.InsertNode(g.Rows.Count, ReplyGroupLevel);
            node.Row[TreeColumnIndex] = group.Name;
            node.Row.UserData = group;
            g.SetCellCheck(node.Row.Index, TreeColumnIndex, checkEnumStatus);
            return node;
        }
        #endregion //AddReplyGroup

        #region _flex_AfterEdit
        private void _flex_AfterEdit(object sender, C1.Win.C1FlexGrid.RowColEventArgs e)
        {
            var row = _flex.Rows[e.Row];
            C1.Win.C1FlexGrid.CheckEnum checkEnum = _flex.GetCellCheck(e.Row, e.Col);
            if (checkEnum == C1.Win.C1FlexGrid.CheckEnum.TSGrayed)
            {
                _flex.SetCellCheck(e.Row, e.Col, C1.Win.C1FlexGrid.CheckEnum.TSChecked);
                checkEnum = C1.Win.C1FlexGrid.CheckEnum.TSChecked;
            }

            if (row.UserData is ReplyGroup)
            {
                ReplyGroup replyGroup = (ReplyGroup)row.UserData;

                int beginIdx = e.Row + 1;
                for (int i = 0; i < row.Node.Children; i++)
                {
                    int rowIdx = beginIdx + i;
                    _flex.SetCellCheck(rowIdx, e.Col, checkEnum);
                    ReplyItem ri = (ReplyItem)_flex.Rows[rowIdx].UserData;
                    ri.Enabled = CheckEnumToBool(checkEnum);
                    Console.WriteLine(ri.Name + " " + ri.Enabled);
                }
            }

            if (row.UserData is ReplyItem)
            {
                ReplyItem ri = (ReplyItem)row.UserData;
                C1.Win.C1FlexGrid.CheckEnum ce = _flex.GetCellCheck(row.Index, TreeColumnIndex);
                bool b = (ce == C1.Win.C1FlexGrid.CheckEnum.Checked) ||
                    (ce == C1.Win.C1FlexGrid.CheckEnum.TSChecked);

                ri.Enabled = b;

                var groupNode = row.Node.GetNode(C1.Win.C1FlexGrid.NodeTypeEnum.Parent);
                SetGroupCheckStatusByChild(groupNode);
            }
        }
        #endregion //_flex_AfterEdit

        #region CheckEnumToBool
        private bool CheckEnumToBool(CheckEnum ce)
        {
            return (ce == CheckEnum.Checked) || (ce == CheckEnum.TSChecked);
        }
        #endregion //CheckEnumToBool

        #region SetGroupCheckStatusByChild
        private void SetGroupCheckStatusByChild(C1.Win.C1FlexGrid.Node groupNode)
        {
            CheckEnum ce = GetGroupCheckEnum((ReplyGroup)groupNode.Row.UserData);
            _flex.SetCellCheck(groupNode.Row.Index, TreeColumnIndex, ce);
        }
        #endregion //SetGroupCheckStatusByChild

        #region Dictionary
        private SortedDictionary<ReplyGroup, ReplyList> Sp()
        {
            SortedDictionary<ReplyGroup, ReplyList> gs = new SortedDictionary<ReplyGroup, ReplyList>();

            foreach (var item in _replys)
            {
                if (gs.Keys.Contains(item.ReplyGroup))
                {
                    ((ReplyList)gs[item.ReplyGroup]).Add(item);
                }
                else
                {
                    ReplyList replys = new ReplyList();
                    replys.Add(item);
                    gs[item.ReplyGroup] = replys;
                }
            }
            return gs;
        }
        #endregion //Dictionary

        #region frmReplyManager2_Load
        private void frmReplyManager2_Load(object sender, EventArgs e)
        {
            _flex.Cols[0].Visible = false;
        }
        #endregion //frmReplyManager2_Load


        #region InsertReplyItem
        private Row InsertReplyItem(ReplyItem ri)
        {
            var node = FindGroupNode(ri.ReplyGroup);
            var replyItemNode = node.AddNode(C1.Win.C1FlexGrid.NodeTypeEnum.LastChild, null);
            SetReplyItemRow(replyItemNode.Row, ri);
            return replyItemNode.Row;
        }
        #endregion //InsertReplyItem

        #region FindGroupNode
        private C1.Win.C1FlexGrid.Node FindGroupNode(ReplyGroup replyGroup)
        {
            foreach (C1.Win.C1FlexGrid.Row row in _flex.Rows)
            {
                if (row.UserData is ReplyGroup)
                {
                    if (row.UserData == replyGroup)
                    {
                        return row.Node;
                    }
                }
            }

            return AddReplyGroup(replyGroup, GetGroupCheckEnum(replyGroup));
        }
        #endregion //FindGroupNode

        #region DeleteRow
        private void DeleteRow(int rowIdx)
        {
            _flex.Rows.Remove(rowIdx);

        }
        #endregion //DeleteRow

        #region AddReplyItem
        private void AddReplyItem(ReplyItem ri)
        {
            var node = _flex.Rows.InsertNode(_flex.Rows.Count, ReplyItemLevel);
            var row = node.Row;
            SetReplyItemRow(row, ri);
        }
        #endregion //AddReplyItem

        #region SetReplyItemRow
        private void SetReplyItemRow(C1.Win.C1FlexGrid.Row row, ReplyItem ri)
        {
            int col = 1;
            row[col++] = ri.Name;
            row[col++] = ri.ReceivedPattern;
            row[col++] = HexStringConverter.Default.ConvertToObject(ri.ReplyBytes).ToString();
            row[col++] = ri.Description;
            row.UserData = ri;

            _flex.SetCellCheck(row.Index, TreeColumnIndex,
                ri.Enabled ?
                C1.Win.C1FlexGrid.CheckEnum.Checked :
                C1.Win.C1FlexGrid.CheckEnum.Unchecked);
        }
        #endregion //SetReplyItemRow

        #region tsbAdd_Click
        private void tsbAdd_Click(object sender, EventArgs e)
        {
            ReplyGroup rp = ReplyGroupManager.Instance.ReplyGroups.GetFirstOrDefault();
            if (_flex.Row  >0 )
            {
                Row selectedRow = _flex.Rows[_flex.Row];
                object tag = selectedRow.UserData ;
                if (tag is ReplyGroup )
                {
                    rp = tag as ReplyGroup;
                }
                else if ( tag is ReplyItem )
                {
                    rp = ((ReplyItem )tag).ReplyGroup;
                }
            }

            frmReplyItem f = new frmReplyItem(rp);
            if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                Row row = InsertReplyItem(f.ReplyItem);
                _flex.Row = row.Index;
                App.Default.ReplyManager.ReplyCollection.Add(f.ReplyItem);
            }
        }
        #endregion //tsbAdd_Click

        #region tsbEdit_Click
        private void tsbEdit_Click(object sender, EventArgs e)
        {
            int rowIdx = _flex.Row;
            if (rowIdx <= 0)
            {
                return;
            }

            var row = _flex.Rows[rowIdx];
            object userData = row.UserData;
            ReplyItem ri = userData as ReplyItem;
            if (ri != null)
            {
                ReplyGroup oldGroup = ri.ReplyGroup;

                frmReplyItem f = new frmReplyItem(ri);
                if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    if (ri.ReplyGroup == oldGroup)
                    {
                        SetReplyItemRow(row, ri);
                    }
                    else
                    {
                        DeleteRow(rowIdx);
                        Row insertRow = InsertReplyItem(ri);
                        _flex.Row = insertRow.Index;
                    }
                }
            }

            ReplyGroup rg = userData as ReplyGroup;
            if (rg != null)
            {
                frmReplyGroup f = new frmReplyGroup(rg);
                if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    row[TreeColumnIndex] = rg.Name;
                }
            }
        }
        #endregion //tsbEdit_Click


        #region tsbDelete_Click
        private void tsbDelete_Click(object sender, EventArgs e)
        {
            int rowIdx = _flex.Row;
            if (rowIdx > 0)
            {
                Row row = _flex.Rows[rowIdx];
                string name = row[TreeColumnIndex].ToString();
                if (NUnit.UiKit.UserMessage.Ask(
                    string.Format(Strings.AreYouSureDeleteItem, name)) 
                    == DialogResult.Yes)
                {
                    ReplyItem ri = _flex.Rows[rowIdx].UserData as ReplyItem;
                    if (ri != null)
                    {
                        DeleteRow(rowIdx);
                        App.Default.ReplyManager.ReplyCollection.Remove(ri);
                        return;
                    }

                    ReplyGroup rg = _flex.Rows[rowIdx].UserData as ReplyGroup;
                    if (rg != null)
                    {
                        Row rowRg = _flex.Rows[rowIdx];
                        _flex.Rows.RemoveRange(rowRg.Index, rowRg.Node.Children + 1);
                        App.Default.ReplyManager.ReplyCollection.Remove(rg);
                    }
                }
            }
        }
        #endregion //tsbDelete_Click

        #region tsbExpand_Click
        private void tsbExpand_Click(object sender, EventArgs e)
        {
            ExpandOrPackup(true);
        }

        private void ExpandOrPackup(bool expand)
        {
            foreach (Row row in _flex.Rows)
            {
                if (row.IsNode)
                {
                    row.Node.Expanded = expand;
                }
            }
        }
        #endregion //tsbExpand_Click

        #region tsbPackup_Click
        private void tsbPackup_Click(object sender, EventArgs e)
        {
            ExpandOrPackup(false);
        }
        #endregion //tsbPackup_Click
    }
}
